﻿using System;
using System.Collections;
using System.Collections.Generic;
using QFramework;
using UnityEngine;
using YooAsset;
using Object = UnityEngine.Object;
using static Gp.Scripts.Core.Res.ResPackageManager;

namespace Gp.Scripts.Core.Res
{
    public class ResLoader : IPoolable
    {
        private List<AssetHandle> _handles;
        
        [Obsolete("请使用 ResLoader.Allocate() 获取 ResLoader 对象", true)]
        public ResLoader() { _handles = new List<AssetHandle>(); }
        
        public static ResLoader Allocate()
        {
            return SafeObjectPool<ResLoader>.Instance.Allocate();
        }

        public void Recycle2Cache()
        {
            SafeObjectPool<ResLoader>.Instance.Recycle(this);
        }

        public bool IsRecycled { get; set; }
        bool IPoolable.IsRecycled { get; set; }

        void IPoolable.OnRecycled()
        {
            ReleaseAllRes();
        }

        /// <summary>
        /// 根据资源组名和文件名载入
        /// </summary>
        /// <param name="bundleName">对应资源组名。如character、ui</param>
        /// <param name="assetName">资源文件名</param>
        public T LoadSync<T>(string bundleName, string assetName) where T : Object
        {
            return LoadSyncProcess<T>($"{bundleName}_{assetName}");
        }

        public T LoadSync<T>(string assetPath) where T : Object
        {
            return LoadSyncProcess<T>(assetPath);
        }

        private T LoadSyncProcess<T>(string resLoadKey) where T : Object
        {
            Debug.Log("Loading: " + resLoadKey);
            AssetHandle handle = null;
            T           ret    = null;
            if (typeof(Component).IsAssignableFrom(typeof(T)))
            {
                handle = ResPackage.LoadAssetSync<GameObject>(resLoadKey);
                if (handle.GetAssetObject<GameObject>().TryGetComponent<T>(out var com)) { ret = com; }
                else
                {
                    handle.Release();
                    throw new Exception("type error: " + resLoadKey + ", not found component " + typeof(T));
                }
            }
            else
            { 
                handle = ResPackage.LoadAssetSync<T>(resLoadKey);
                ret    = handle.GetAssetObject<T>();
            } 
            _handles.Add(handle);
            return ret;
        }
        
        private void ReleaseAllRes()
        {
            _handles.ForEach(x => x.Release());
            _handles.Clear();
        }


        public AsyncLoaderHandle LoadAsyncProcess<T>(string resLoadKey) where T : Object
        {
            var handle = YooAssets.LoadAssetAsync<T>(resLoadKey);
            return new AsyncLoaderHandle(handle);
        }
        
    }

    public readonly struct AsyncLoaderHandle
    {
        private readonly AssetHandle _handle;
        public AsyncLoaderHandle(AssetHandle handle)
        {
            _handle = handle;
        }

        public IEnumerator Wait()
        {
            yield return _handle.Task;
        }

        public void BlockUntilCompleted()
        {
            _handle.WaitForAsyncComplete();
        }
    }
}